import { IsString, IsOptional, IsObject, ValidateNested, IsArray, IsEnum, IsNumber, IsDate, IsInt, Min, Max } from 'class-validator'
import { Type } from 'class-transformer'
import { WorkflowTemplate, TemplateMetadata, TemplateParams } from '../comfy/schemas/workflow-template.schema'

export class SamplerDto {
    @IsString()
    name: string

    @IsString()
    @IsOptional()
    scheduler?: string

    @IsInt()
    @Min(1)
    @Max(150)
    steps: number

    @IsNumber()
    @Min(1)
    @Max(20)
    cfg: number

    @IsNumber()
    @IsOptional()
    denoise?: number

    @IsNumber()
    @IsOptional()
    seed?: number
}

export class ControlNetPreprocessorDto {
    @IsNumber()
    @IsOptional()
    low_threshold?: number

    @IsNumber()
    @IsOptional()
    high_threshold?: number
}

export class ControlNetDto {
    @IsString()
    type: string

    @IsNumber()
    @Min(0)
    @Max(1)
    strength: number

    @IsString()
    @IsOptional()
    image?: string

    @IsObject()
    @IsOptional()
    @ValidateNested()
    @Type(() => ControlNetPreprocessorDto)
    preprocessor?: ControlNetPreprocessorDto
}

export class LoraDto {
    @IsString()
    name: string

    @IsNumber()
    @Min(0)
    @Max(1)
    strength: number
}

export class CreateTemplateDto implements Partial<WorkflowTemplate> {
    @IsString()
    id: string

    @IsString()
    name: string

    @IsString()
    @IsOptional()
    description?: string

    @IsString()
    category: string

    @IsObject()
    workflow: any

    @IsObject()
    @ValidateNested()
    @Type(() => TemplateParamsDto)
    defaultParams: TemplateParams

    @IsObject()
    @ValidateNested()
    @Type(() => TemplateMetadataDto)
    metadata: TemplateMetadata
}

export class TemplateParamsDto implements TemplateParams {
    @IsString()
    prompt: string

    @IsString()
    negativePrompt: string

    @IsNumber()
    width: number

    @IsNumber()
    height: number

    @IsNumber()
    @IsOptional()
    seed?: number

    @IsObject()
    @ValidateNested()
    @Type(() => SamplerDto)
    sampler: {
        name: string
        scheduler?: string
        steps: number
        cfg: number
        denoise?: number
        seed?: number
    }

    @IsObject()
    @IsOptional()
    @ValidateNested()
    @Type(() => ControlNetDto)
    controlnet?: {
        type: string
        strength: number
        image?: string
        preprocessor?: {
            low_threshold?: number
            high_threshold?: number
        }
    }

    @IsObject()
    @IsOptional()
    @ValidateNested()
    @Type(() => LoraDto)
    lora?: {
        name: string
        strength: number
    }
}

export class TemplateMetadataDto implements TemplateMetadata {
    @IsEnum(['sdxl', 'controlnet', 'lora'])
    type: 'sdxl' | 'controlnet' | 'lora'

    @IsString()
    @IsOptional()
    controlType?: string

    @IsString()
    @IsOptional()
    loraName?: string

    @IsNumber()
    @IsOptional()
    loraWeight?: number

    @IsArray()
    @IsString({ each: true })
    tags: string[]

    @IsString()
    author: string

    @IsString()
    version: string

    @IsDate()
    createTime: Date

    @IsDate()
    updateTime: Date
}

export class UpdateTemplateDto extends CreateTemplateDto {
    @IsOptional()
    id: string

    @IsOptional()
    name: string

    @IsOptional()
    category: string

    @IsOptional()
    workflow: any

    @IsOptional()
    defaultParams: TemplateParams

    @IsOptional()
    metadata: TemplateMetadata
}